## Функция как параметр функции

Поскольку функция в Python может представлять такое же значение как строка или число, соответственно мы можем передать ее в качестве параметра в другую функцию. 

Например, определим функцию, которая выводит на консоль результат некоторой операции:

```python
def do(a, b, op):
    return op(a, b)


def sum(a, b):
    return a + b


def multiply(a, b):
    return a * b


print(do(5,5,sum))
print(do(5,5,multiply))

```

В данном случае функция do_operation имеет три параметра, причем третий параметр, как предполагается, будет представлять функцию, которая принимает два параметра и возвращает некоторый результат. 

Иными словами третий параметр - `operation` представляет некоторую операцию, но на момент определения функции `do_operation` мы точно не знаем, что это будет за операция. 

Мы только знаем, что она принимает два параметр и возвращает какой-то результат, который потом выводится на консоль.

При вызове функции do_operation мы сможем передать в качестве третьего параметра другую функцию, например, функцию sum:

>def do(a, b, op):

То есть в данном случае параметр operation фактически будет представлять функцию sum и будет возвращать сумму дву чисел.

Затем аналогичным образов в вызов функции `do_operation` можно передать третьему параметру другую функцию - `multiply`, которая выполнит умножение чисел:

>print(do(5,5,multiply))

Таким образом, более гибкие по функциональности функции, которые через параметры принимают другие функции.


## Функция как результат функции

Также одна функция в Python может возвращать другую функцию. Например, определим функцию, которая в зависимости от значения параметра возвращает ту или иную операцию:

```python
def sum(a, b): return a + b


def subtract(a, b): return a - b


def multiply(a, b): return a * b


def select_operation(choice):
    if choice == 1:
        return sum
    elif choice == 2:
        return subtract
    else:
        return multiply


operation = select_operation(1)  # operation = sum
print(operation(10, 6))  # 16

operation = select_operation(2)  # operation = subtract
print(operation(10, 6))  # 4

operation = select_operation(3)  # operation = multiply
print(operation(10, 6))  # 60
```


В данном случае функция select_operation в зависимости от значения параметра choice возвращает одну из трех функций - `sum`, `subtract` и `multiply`. Затем мы мы можем получить результат функции `select_operation` в переменную `operation`:

>operation = select_operation(1)

Так, в данном случае в функцию select_operation передается число 1, соответственно она будет возвращать функцию sum. Поэтому переменная operation фактически будет указывать на функцию sum, которая выполняет сложение двух чисел:

```python
print(operation(10, 6)) # 16 - фактически равно sum(10, 6)
```

### Фабрика функций

```python
def func1(num):
  return num + 1


def func2(num):
  return num * 2


my_dict = {'func1': func1, 'func2': func2}

# Передадим в функции число 2:
my_dict['func1'](2) 
# 3
my_dict['func2'](2) 
# 4
```


```python
# словарь с функциями
calc = {
    "plus": lambda x, y: x + y,
    "minus": lambda x, y: x - y,
    "division": lambda x, y: x / y,
    # в качестве значения можно использовать 
    # встроенную функцию pow() или любую 
    # пользовательскую функцию 
    "power": pow
}

def action(match, dictionary, default="NO CALC"):
    """шаблон фабрики функций"""
    if match in dictionary:
        return dictionary[match]
    return lambda *x: default



plus = action('plus', calc)
minus = action('minus', calc)
power = action('power', calc)
square = action('square', calc)
plus(5, 4)
# 9
minus(5, 4)
# 1
power(3, 3)
# 27
square(1, 1)
'NO CALC'
square(1)
'NO CALC'
```

Где можно использовать шаблон `Фабрика функций`?

Представьте ситуацию, что есть некий код, который по условию `if/elif/else` как-то обрабатывает данные, например, преобразует их в формат JSON или YAML или в список кортежей или делает что-то еще. 

Обратите внимание, что код обработки данных в каждом блоке `if` или elif` может быть огромным. 

Как результат, он плохо читается и его трудно поддерживать, а также его нельзя использовать повторно. В таких ситуациях приходит на помощь фабрика функций.